package com.marketsim.dao;

import com.marketsim.common.bean.HistoryPriceBean;
import com.marketsim.simulator.PricesHistoricalData;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

public class StockTickerDAO {
    private static final Log log = LogFactory.getLog(StockTickerDAO.class);
    private static final StockTickerDAO stockDAO = new StockTickerDAO();

    private ThreadPoolExecutor executor =
            new ThreadPoolExecutor(10, 10, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

    private StockTickerDAO() {
    }

    public static StockTickerDAO getInstance() {
        return stockDAO;
    }

    public PricesHistoricalData getStockInfo(List<String> symbols, final Date startDate, final Date endDate) {
        List<List<HistoryPriceBean>> result = new LinkedList<>();
        Collection<Future<List<HistoryPriceBean>>> futures = new LinkedList<>();
        for (final String symbol : symbols) {
            futures.add(executor.submit(new Callable<List<HistoryPriceBean>>() {
                @Override
                public List<HistoryPriceBean> call() throws Exception {
                    return getStockInfo(symbol, startDate, endDate);
                }
            }));
        }

        for (Future<List<HistoryPriceBean>> future : futures) {
            try {
                result.add(future.get());
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
        return new PricesHistoricalData(result, symbols);
    }

    public List<HistoryPriceBean> getStockInfo(String symbol, Date startDate, Date endDate) {
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

        Integer startMonth = startCal.get(Calendar.MONTH);
        Integer startDay = startCal.get(Calendar.DAY_OF_MONTH);
        Integer startYear = startCal.get(Calendar.YEAR);
        Integer endMonth = endCal.get(Calendar.MONTH);
        Integer endDay = endCal.get(Calendar.DAY_OF_MONTH);
        Integer endYear = endCal.get(Calendar.YEAR);

        Formatter formatter = new Formatter(new StringBuilder(), Locale.US);
        String urlTemplate = "http://ichart.finance.yahoo.com/table.csv?s=%s&a=%02d&b=%d&c=%d&d=%02d&e=%02d&f=%d&g=d&ignore=.csv";
        String url = String.format(urlTemplate, symbol, startMonth, startDay, startYear, endMonth, endDay, endYear);

        List<HistoryPriceBean> result = new LinkedList<>();
        try {
            URL yahooFin = new URL(url);
            URLConnection yc = yahooFin.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

            DateFormat dateFormat = new SimpleDateFormat("yyyy-M-d", Locale.ENGLISH);
            String inputLine;
            //skip first line
            in.readLine();
            while ((inputLine = in.readLine()) != null) {
                String[] yahooStockInfo = inputLine.split(",");
                HistoryPriceBean priceBean = new HistoryPriceBean();
                priceBean.setTicker(symbol);
                priceBean.setDate(dateFormat.parse(yahooStockInfo[0]));
                priceBean.setOpen(new BigDecimal((yahooStockInfo[1])));
                priceBean.setHigh(new BigDecimal((yahooStockInfo[2])));
                priceBean.setLow(new BigDecimal((yahooStockInfo[3])));
                priceBean.setClose(new BigDecimal((yahooStockInfo[4])));
                priceBean.setVolume(Long.valueOf(yahooStockInfo[5]));
                priceBean.setAdjClose(new BigDecimal((yahooStockInfo[6])));
                result.add(priceBean);
            }
            in.close();
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
}
